#ifndef RT_SSL_HPP__
#define RT_SSL_HPP__

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>

#include <openssl/md5.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/des.h>

// copy from <debug.hpp> [0.2.3]
#define __RT__DEBUG 1
#define nullptr NULL

#ifdef __cplusplus
    #define CharArray(name, n) char name[n]={}
    #define UCharArray(name, n) unsigned char name[n]={}
#else
    #define CharArray(name, n) \
    char name[n]; memset(name,0,n)
    #define UCharArray(name, n) \
    unsigned char name[n]; memset(name,0,n)
#endif

#define _print(note, ...) \
{	if(__RT__DEBUG) \
    printf("-- DEBUG -->> " note "\n",  ##__VA_ARGS__); }

// C-type Exception
#include <setjmp.h>

#define SEXCEPTION Except_SSL
enum ExceptEnum_SSL{
    Base64_Enc_Err = 1,
    Base64_Dec_Err,
    DES_Enc_Err,
    DES_Dec_Err,
    AES_Enc_Err,
    AES_Dec_Err,
    RSA_PubKey_Enc_Err,
    RSA_PrivKey_Dec_Err,
    RSA_PrivKey_Enc_Err,
    RSA_PubKey_Dec_Err,
    Load_Key_Err,
    MD5_File_Err
};

#define ExceptLink_Desciption_Length 64
struct ExceptLink{
    jmp_buf jmp_buffer;
    char description[ExceptLink_Desciption_Length];
};

struct ExceptLink SEXCEPTION;

#define TRY(module_except) \
    { int jmp_err = setjmp(module_except.jmp_buffer); \
    if (0 == jmp_err)

#define CATCH(ExceptEnum) \
    else if (ExceptEnum == jmp_err)

#define ELSE else
#define ENDTRY }

/*-----------------------------------------------------------------*\
    SSL Functions Define
\*-----------------------------------------------------------------*/
void _hex_show_char(unsigned char *str, int len);  // default len=0

// 需要手动释放内存，default len=0
char* _hex_switch_char(unsigned char *str, int len);

// 对于明文，len可以置零（NULL），default len=0
char* md5_string(char* to, const char *from, int len);

char* md5_file(char* to, const char *file_path);

char* encode_base64(char* to, const char* from, int len);

//  缺陷：EVP_DecodeBlock() 无法返回原始字符串长度（由于末位补零）
char* decode_base64(char* to, const char* from, int len);

char* encrypt_des(char* to, const char* from, int len_from, const char* strkey);

char* decrypt_des(char* to, const char* from, int len, const char* strkey);


/*-----------------------------------------------------------------*\
    RSA Encrypt
\*-----------------------------------------------------------------*/

RSA* rsa_load_keyfile(const char* file_path, bool isPubkey);

bool rsa_free_keyfile(RSA* key);

char* rsa_error();

// 注意：公钥加密生成的加密字符串为随机值，密文并不一致，但不影响解密
char* encrypt_rsa_pubkey(char* to, const char* from, int len_from, RSA* key);

char* decrypt_rsa_privkey(char* to, const char* from, int len_from, RSA* key);

// 私钥加密生成的密文是一致的
char* encrypt_rsa_privkey(char* to, const char* from, int len_from, RSA* key);

char* decrypt_rsa_pubkey(char* to, const char* from, int len_from, RSA* key);

#endif  // RT_SSL_HPP__
